﻿namespace TestTool.Tests.Engine
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Threading;
    using TestTool.HttpTransport.Interfaces;
    using TestTool.Tests.Definitions.Data;
    using TestTool.Tests.Definitions.Enums;
    using TestTool.Tests.Definitions.Interfaces;
    using TestTool.Tests.Definitions.Trace;
    using TestTool.Tests.Engine.Base.Definitions;
    using TestTool.Tests.Engine.Base.TestBase;

    public class TestDispatcher
    {
        private ITest _currentTest;
        private TestInfo _currentTestInfo;
        private bool _delayedHalt;
        private TestTool.Tests.Engine.DeviceInformation _deviceInformation;
        private bool _dispatcherLevelPause;
        private List<IProfileDefinition> _failedProfiles = new List<IProfileDefinition>();
        private List<Feature> _features = new List<Feature>();
        private bool _featuresDefined;
        private ManualResetEvent _haltEvent = new ManualResetEvent(false);
        private TestSuiteParameters _parameters;
        private object _pauseSync = new object();
        private ManualResetEvent _resumeEvent = new ManualResetEvent(false);
        private List<string> _scopes = new List<string>();
        private bool _shutDownInProgress;
        private TestState _state;
        private bool _stop;
        private List<IProfileDefinition> _supportedProfiles = new List<IProfileDefinition>();
        private List<Feature> _undefinedFeatures = new List<Feature>();
        private List<Feature> _unsupportedFeatures = new List<Feature>();
        private List<IProfileDefinition> _unsupportedProfiles = new List<IProfileDefinition>();

        public event Action<TestTool.Tests.Engine.DeviceInformation> DeviceInformationReceived;

        public event Action<Feature, bool> FeatureDefined;

        public event Action<Feature> FeatureDefinitionFailed;

        public event Action<ConformanceInitializationData> InitializationCompleted;

        public event Action<Exception> OnException;

        public event Action Paused;

        public event ProfileDefinitionCompletedHandler ProfileDefinitionCompleted;

        public event Action<string> RequestSent;

        public event Action<string> ResponseReceived;

        public event TestTool.Tests.Definitions.Trace.StepCompleted StepCompleted;

        public event Action<string> StepEvent;

        public event Action<StepResult> StepStarted;

        public event TestCompletedHandler TestCompleted;

        public event Action<string> TestEvent;

        public event Action<TestInfo> TestStarted;

        public event Action<TestSuiteParameters, bool> TestSuiteCompleted;

        private void fdp_DeviceInformationReceived(TestTool.Tests.Engine.DeviceInformation data)
        {
            this._deviceInformation = data;
            if (this.DeviceInformationReceived != null)
            {
                this.DeviceInformationReceived(data);
            }
        }

        private void fdp_FeatureDefined(Feature feature, bool supported)
        {
            if (this._undefinedFeatures.Contains(feature))
            {
                this._undefinedFeatures.Remove(feature);
            }
            if (supported)
            {
                if (!this._features.Contains(feature))
                {
                    this._features.Add(feature);
                }
                if (this._unsupportedFeatures.Contains(feature))
                {
                    this._unsupportedFeatures.Remove(feature);
                }
            }
            else
            {
                if (!this._unsupportedFeatures.Contains(feature))
                {
                    this._unsupportedFeatures.Add(feature);
                }
                if (this._features.Contains(feature))
                {
                    this._features.Remove(feature);
                }
            }
            if (this.FeatureDefined != null)
            {
                this.FeatureDefined(feature, supported);
            }
        }

        private void fdp_FeatureDefinitionFailed(Feature feature)
        {
            if (!this._undefinedFeatures.Contains(feature))
            {
                this._undefinedFeatures.Add(feature);
            }
            if (this._features.Contains(feature))
            {
                this._features.Remove(feature);
            }
            if (this._unsupportedFeatures.Contains(feature))
            {
                this._unsupportedFeatures.Remove(feature);
            }
            if (this.FeatureDefinitionFailed != null)
            {
                this.FeatureDefinitionFailed(feature);
            }
        }

        private void fdp_ScopeDefined(string scope)
        {
            this._scopes.Add(scope);
        }

        public void Halt()
        {
            this._stop = true;
            if (this._currentTest != null)
            {
                this._currentTest.Halt();
            }
            this._haltEvent.Set();
            lock (this._pauseSync)
            {
                this._delayedHalt = true;
            }
        }

        private void InitConformanceTesting(TestLaunchParam param)
        {
            param.Features.Clear();
            param.Features.AddRange(this._features);
            param.Features.AddRange(this._undefinedFeatures);
            if (this._features.Contains(Feature.Digest))
            {
                param.Security = Security.Digest;
            }
            else
            {
                param.Security = Security.WS;
            }
        }

        private BaseTest InitCurrentTest(TestInfo testInfo, Type[] types, object[] args)
        {
            BaseTest test = (BaseTest) testInfo.Method.DeclaringType.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.HasThis, types, null).Invoke(args);
            this._currentTest = test;
            this.SubscribeToTestEvents(test);
            if (testInfo.ProcessType == ProcessType.FeatureDefinition)
            {
                FeaturesDefinitionProcess process = (FeaturesDefinitionProcess) test;
                process.FeatureDefined += new Action<Feature, bool>(this.fdp_FeatureDefined);
                process.FeatureDefinitionFailed += new Action<Feature>(this.fdp_FeatureDefinitionFailed);
                process.ScopeDefined += new Action<string>(this.fdp_ScopeDefined);
                process.DeviceInformationReceived += new Action<TestTool.Tests.Engine.DeviceInformation>(this.fdp_DeviceInformationReceived);
            }
            this._currentTest.EntryPoint = testInfo.Method;
            return test;
        }

        public void Pause()
        {
            this._state = TestState.Paused;
            if (this._currentTest != null)
            {
                this._currentTest.Pause();
            }
            else
            {
                if (this.Paused != null)
                {
                    this.Paused();
                }
                lock (this._pauseSync)
                {
                    this._dispatcherLevelPause = true;
                }
            }
        }

        private void pst_ProfileDefinitionCompleted(IProfileDefinition profile, ProfileStatus status, string dump)
        {
            switch (status)
            {
                case ProfileStatus.NotSupported:
                    this._unsupportedProfiles.Add(profile);
                    break;

                case ProfileStatus.Supported:
                    this._supportedProfiles.Add(profile);
                    break;

                case ProfileStatus.Failed:
                    this._failedProfiles.Add(profile);
                    break;
            }
            if (this.ProfileDefinitionCompleted != null)
            {
                this.ProfileDefinitionCompleted(profile, status, dump);
            }
        }

        private void ReportException(Exception ex)
        {
            if ((this.OnException != null) && !this._shutDownInProgress)
            {
                this.OnException(ex);
            }
        }

        private void ReportInitializationCompleted(IEnumerable<TestInfo> tests, bool toBeContinued)
        {
            if (this.InitializationCompleted != null)
            {
                ConformanceInitializationData data = new ConformanceInitializationData {
                    DeviceInformation = this._deviceInformation
                };
                data.TestsSelected.AddRange(tests);
                data.FailedProfiles.AddRange(this._failedProfiles);
                data.SupportedProfiles.AddRange(this._supportedProfiles);
                data.UnsupportedProfiles.AddRange(this._unsupportedProfiles);
                data.SupportedFeatures.AddRange(this._features);
                data.UnsupportedFeatures.AddRange(this._unsupportedFeatures);
                data.UndefinedFeatures.AddRange(this._undefinedFeatures);
                data.Continue = toBeContinued;
                this.InitializationCompleted(data);
            }
        }

        public void RequestFeatures(TestSuiteParameters parameters)
        {
            parameters.TestCases.Clear();
            parameters.TestCases.Add(FeaturesDefinitionProcess.This);
            this.Run(parameters);
        }

        public void ResetFeatures()
        {
            this._features.Clear();
            this._undefinedFeatures.Clear();
            this._unsupportedFeatures.Clear();
            this._scopes.Clear();
            this._supportedProfiles.Clear();
            this._unsupportedProfiles.Clear();
            this._failedProfiles.Clear();
            this._featuresDefined = false;
        }

        public void Resume()
        {
            bool flag;
            this._state = TestState.Running;
            lock (this._pauseSync)
            {
                flag = this._dispatcherLevelPause;
            }
            if (flag)
            {
                this._resumeEvent.Set();
            }
            else if (this._currentTest != null)
            {
                this._currentTest.Resume();
            }
        }

        public void Run(TestSuiteParameters parameters)
        {
            this._parameters = parameters;
            lock (this._pauseSync)
            {
                this._stop = false;
                this._delayedHalt = false;
                this._dispatcherLevelPause = false;
            }
            this._state = TestState.Running;
            new Thread(new ThreadStart(this.RunTests)) { CurrentUICulture = CultureInfo.InvariantCulture }.Start();
        }

        private void RunTests()
        {
            Type[] types = new Type[] { typeof(TestLaunchParam) };
            bool flag = false;
            TestLaunchParam param = new TestLaunchParam {
                ServiceAddress = this._parameters.Address,
                CameraIp = this._parameters.CameraIP,
                CameraUUID = this._parameters.CameraUUID,
                NIC = this._parameters.NetworkInterfaceController,
                MessageTimeout = this._parameters.MessageTimeout,
                RebootTimeout = this._parameters.RebootTimeout,
                UserName = this._parameters.UserName,
                Password = this._parameters.Password,
                UseUTCTimestamp = this._parameters.UseUTCTimestamp,
                Operator = this._parameters.Operator,
                VideoForm = this._parameters.VideoForm,
                EnvironmentSettings = this._parameters.EnvironmentSettings,
                PTZNodeToken = this._parameters.PTZNodeToken,
                UseEmbeddedPassword = this._parameters.UseEmbeddedPassword,
                Password1 = this._parameters.Password1,
                Password2 = this._parameters.Password2,
                OperationDelay = this._parameters.OperationDelay,
                RecoveryDelay = this._parameters.RecoveryDelay,
                SecureMethod = this._parameters.SecureMethod,
                SubscriptionTimeout = this._parameters.SubscriptionTimeout,
                EventTopic = this._parameters.EventTopic,
                TopicNamespaces = this._parameters.TopicNamespaces,
                RelayOutputDelayTimeMonostable = this._parameters.RelayOutputDelayTimeMonostable,
                RecordingToken = this._parameters.RecordingToken,
                SearchTimeout = this._parameters.SearchTimeout,
                MetadataFilter = this._parameters.MetadataFilter,
                RetentionTime = this._parameters.RetentionTime,
                AdvancedPrameters = this._parameters.AdvancedParameters
            };
            object[] args = new object[] { param };
            int num = 0;
            List<TestInfo> list = new List<TestInfo>();
            bool flag2 = this._featuresDefined;
            switch (this._parameters.FeatureDefinition)
            {
                case TestTool.Tests.Engine.FeatureDefinitionMode.Default:
                    param.Features.AddRange(this._features);
                    break;

                case TestTool.Tests.Engine.FeatureDefinitionMode.AssumeSupported:
                    flag2 = true;
                    param.FeatureDefinitionMode = TestTool.Tests.Engine.Base.Definitions.FeatureDefinitionMode.AllSupported;
                    break;

                case TestTool.Tests.Engine.FeatureDefinitionMode.AssumeNotSupported:
                    param.FeatureDefinitionMode = TestTool.Tests.Engine.Base.Definitions.FeatureDefinitionMode.AllNotSupported;
                    flag2 = true;
                    break;
            }
            if (!flag2)
            {
                list.Add(FeaturesDefinitionProcess.This);
                param.Security = Security.None;
            }
            else
            {
                if (this._features.Contains(Feature.Digest) || (this._parameters.FeatureDefinition == TestTool.Tests.Engine.FeatureDefinitionMode.AssumeSupported))
                {
                    param.Security = Security.Digest;
                }
                else
                {
                    param.Security = Security.WS;
                }
                bool toBeContinued = (this._parameters.TestCases.Count == 0) && (this._parameters.FeatureDefinition != TestTool.Tests.Engine.FeatureDefinitionMode.Define);
                if (toBeContinued)
                {
                    List<Feature> features = new List<Feature>();
                    features.AddRange(this._features);
                    features.AddRange(this._undefinedFeatures);
                    List<TestInfo> collection = ConformanceLogicHandler.GetTestsByFeatures(this._parameters.AllTestCases, features, this._parameters.Conformance);
                    this._parameters.TestCases.AddRange(collection);
                    this.ReportInitializationCompleted(collection, toBeContinued);
                }
            }
            if ((this._parameters.TestCases.Count > 0) && ((this._parameters.TestCases.Count != 1) || (this._parameters.TestCases[0].ProcessType != ProcessType.FeatureDefinition)))
            {
                list.AddRange(this._parameters.TestCases);
            }
            for (int i = 0; i < list.Count; i++)
            {
                TestInfo info = list[i];
                this._currentTestInfo = info;
                if (this._stop)
                {
                    flag = false;
                    break;
                }
                try
                {
                    bool flag4;
                    bool flag6;
                    lock (this._pauseSync)
                    {
                        flag4 = this._dispatcherLevelPause;
                    }
                    if (flag4 && !this.Sleep())
                    {
                        flag = false;
                        break;
                    }
                    if (this.TestStarted != null)
                    {
                        this.TestStarted(info);
                    }
                    this._currentTest = null;
                    BaseTest test = this.InitCurrentTest(info, types, args);
                    lock (this._pauseSync)
                    {
                        flag6 = this._delayedHalt || this._stop;
                    }
                    if (flag6)
                    {
                        flag = false;
                        break;
                    }
                    lock (this._pauseSync)
                    {
                        flag4 = this._dispatcherLevelPause;
                    }
                    if (flag4 && !this.Sleep())
                    {
                        flag = false;
                        break;
                    }
                    this._currentTest.Start();
                    num++;
                    if (info.ProcessType == ProcessType.FeatureDefinition)
                    {
                        if (test.Halted)
                        {
                            break;
                        }
                        ProfilesSupportTest test2 = new ProfilesSupportTest();
                        test2.ProfileDefinitionCompleted += new ProfilesSupportTest.ProfileDefinitionCompletedHandler(this.pst_ProfileDefinitionCompleted);
                        test2.CheckProfiles(this._parameters.Profiles, this._features, this._scopes);
                        bool flag8 = (this._parameters.TestCases.Count == 0) && (this._parameters.FeatureDefinition != TestTool.Tests.Engine.FeatureDefinitionMode.Define);
                        if (!this._featuresDefined || flag8)
                        {
                            this.InitConformanceTesting(param);
                            this._featuresDefined = true;
                            List<TestInfo> list4 = ConformanceLogicHandler.GetTestsByFeatures(this._parameters.AllTestCases, param.Features, this._parameters.Conformance);
                            if (flag8)
                            {
                                list.AddRange(list4);
                            }
                            this.ReportInitializationCompleted(list4, flag8);
                        }
                    }
                    if (num != list.Count)
                    {
                        this._currentTest = null;
                        int num3 = WaitHandle.WaitAny(new WaitHandle[] { this._haltEvent }, this._parameters.TimeBetweenTests);
                        this._haltEvent.Reset();
                        lock (this._pauseSync)
                        {
                            flag6 = this._delayedHalt || this._stop;
                        }
                        if ((num3 != 0) && !flag6)
                        {
                            continue;
                        }
                        flag = false;
                        break;
                    }
                    if (this._parameters.RepeatTests)
                    {
                        num = 0;
                        i = -1;
                    }
                    flag = true;
                }
                catch (TargetException exception)
                {
                    this._currentTest.ExitTest(exception);
                    this.ReportException(exception);
                    if (info.ProcessType == ProcessType.FeatureDefinition)
                    {
                        break;
                    }
                }
                catch (ArgumentException exception2)
                {
                    this._currentTest.ExitTest(exception2);
                    this.ReportException(exception2);
                }
                catch (TargetParameterCountException exception3)
                {
                    this._currentTest.ExitTest(exception3);
                    this.ReportException(exception3);
                }
                catch (MethodAccessException exception4)
                {
                    this._currentTest.ExitTest(exception4);
                    this.ReportException(exception4);
                }
                catch (InvalidOperationException exception5)
                {
                    this._currentTest.ExitTest(exception5);
                    this.ReportException(exception5);
                }
                catch (Exception exception6)
                {
                    this.ReportException(exception6);
                }
            }
            this._state = TestState.Idle;
            if ((this.TestSuiteCompleted != null) && !this._shutDownInProgress)
            {
                this.TestSuiteCompleted(this._parameters, flag);
            }
        }

        public void Shutdown()
        {
            this._shutDownInProgress = true;
            this.Halt();
        }

        private bool Sleep()
        {
            this._state = TestState.Paused;
            if (this.Paused != null)
            {
                this.Paused();
            }
            int num = WaitHandle.WaitAny(new WaitHandle[] { this._resumeEvent, this._haltEvent });
            if (num == 0)
            {
                this._resumeEvent.Reset();
                lock (this._pauseSync)
                {
                    this._dispatcherLevelPause = false;
                }
            }
            return (num == 0);
        }

        public void Stop()
        {
            lock (this._pauseSync)
            {
                this._stop = true;
            }
        }

        private void SubscribeToTestEvents(BaseTest test)
        {
            test.OnTestCompleted += new TestTool.Tests.Definitions.Trace.TestCompleted(this.test_OnTestCompleted);
            test.OnStepCompleted += new TestTool.Tests.Definitions.Trace.StepCompleted(this.test_OnStepCompleted);
            test.OnStepStarted += new Action<StepResult>(this.test_OnStepStarted);
            test.OnRequestSent += new Action<string>(this.test_OnRequestSent);
            test.OnResponseReceived += new Action<string>(this.test_OnResponseReceived);
            test.OnStepEvent += new Action<string>(this.test_OnStepEvent);
            test.OnTestEvent += new Action<string>(this.test_OnTestEvent);
            test.Paused += new Action(this.test_Paused);
        }

        private void test_OnRequestSent(string obj)
        {
            if ((this.RequestSent != null) && !this._shutDownInProgress)
            {
                this.RequestSent(obj);
            }
        }

        private void test_OnResponseReceived(string obj)
        {
            if ((this.ResponseReceived != null) && !this._shutDownInProgress)
            {
                this.ResponseReceived(obj);
            }
        }

        private void test_OnStepCompleted(StepResult result)
        {
            if ((this.StepCompleted != null) && !this._shutDownInProgress)
            {
                this.StepCompleted(result);
            }
        }

        private void test_OnStepEvent(string obj)
        {
            if ((this.StepEvent != null) && !this._shutDownInProgress)
            {
                this.StepEvent(obj);
            }
        }

        private void test_OnStepStarted(StepResult obj)
        {
            if ((this.StepStarted != null) && !this._shutDownInProgress)
            {
                this.StepStarted(obj);
            }
        }

        private void test_OnTestCompleted(TestLog log)
        {
            if ((this.TestCompleted != null) && !this._shutDownInProgress)
            {
                this.TestCompleted(this._currentTestInfo, log);
            }
        }

        private void test_OnTestEvent(string obj)
        {
            if ((this.TestEvent != null) && !this._shutDownInProgress)
            {
                this.TestEvent(obj);
            }
        }

        private void test_Paused()
        {
            if (this.Paused != null)
            {
                this.Paused();
            }
        }

        public TestInfo CurrentTest
        {
            get
            {
                return this._currentTestInfo;
            }
        }

        public TestTool.Tests.Engine.DeviceInformation DeviceInformation
        {
            get
            {
                return this._deviceInformation;
            }
        }

        public List<Feature> Features
        {
            get
            {
                return this._features;
            }
        }

        public bool FeaturesDefined
        {
            get
            {
                return this._featuresDefined;
            }
        }

        public List<string> Scopes
        {
            get
            {
                return this._scopes;
            }
        }

        public TestState State
        {
            get
            {
                return this._state;
            }
        }

        public List<Feature> UndefinedFeatures
        {
            get
            {
                return this._undefinedFeatures;
            }
        }

        public List<Feature> UnsupportedFeatures
        {
            get
            {
                return this._unsupportedFeatures;
            }
        }

        public delegate void ProfileDefinitionCompletedHandler(IProfileDefinition profile, ProfileStatus status, string dump);

        public delegate void TestCompletedHandler(TestInfo testInfo, TestLog log);
    }
}

